package com.sh.data.engine.domain.normalization.standard.job;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.domain.base.model.enums.Database;
import com.sh.data.engine.domain.common.model.enums.CommonConfigKeyEnum;
import com.sh.data.engine.domain.common.service.CommonService;
import com.sh.data.engine.domain.common.service.ICommonConfigService;
import com.sh.data.engine.domain.dataasset.model.param.SaveNewTblPropParam;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceManagerDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.normalization.standard.model.domain.DictionaryDomain;
import com.sh.data.engine.domain.normalization.standard.model.domain.DictionaryMappingDomain;
import com.sh.data.engine.domain.normalization.standard.model.domain.DictionaryMappingReportDomain;
import com.sh.data.engine.domain.normalization.standard.model.domain.FieldDomain;
import com.sh.data.engine.domain.normalization.standard.model.param.DictMappingParam;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryMappingDetailParam;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryMappingReportParam;
import com.sh.data.engine.domain.normalization.standard.service.impl.DictionaryMappingDetailServiceImpl;
import com.sh.data.engine.domain.normalization.standard.service.impl.DictionaryMappingReportServiceImpl;
import com.sh.data.engine.domain.normalization.standard.service.impl.DictionaryMappingServiceImpl;
import com.sh.data.engine.domain.normalization.standard.service.impl.DictionaryServiceImpl;
import com.sh.data.engine.domain.shims.db.BaseDbManager;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.workspace.index.model.domain.ProjectDomain;
import com.sh.data.engine.domain.workspace.index.service.ProjectService;
import com.sh.data.engine.domain.workspace.manager.service.impl.StorageServiceImpl;
import com.sh.data.engine.job.core.handler.annotation.XxlJob;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import com.sh.data.engine.repository.dao.integration.datasource.entity.DataSourceEntity;
import com.sh.data.engine.repository.dao.workspace.manager.entity.StorageEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author：jingchen.hr
 * @descripion:
 * @data:2/11/202211:02 AM
 */
@Component
public class DictionaryMappingTask {

    @Autowired
    private ProjectService projectService;

    @Autowired
    private ICommonConfigService commonConfigService;

    @Autowired
    private DictionaryServiceImpl dictionaryService;

    @Autowired
    private DictionaryMappingServiceImpl dictionaryMappingService;

    @Autowired
    private DictionaryMappingDetailServiceImpl dictionaryMappingDetailService;

    @Autowired
    private DictionaryMappingReportServiceImpl dictionaryMappingReportService;

    @Autowired
    private DataSourceService datasourceBaseService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private TblPropService tblPropService;

    @Autowired
    private StorageServiceImpl storageServiceImpl;

    private static Logger log =
        LoggerFactory.getLogger(
            DictionaryMappingTask.class);
    private Long lastTaskExecuteTimeStamp, currentTaskExecuteTimeStamp; // 时间戳，单位s

    // 1-全量 2-字典增量 3-hive表增量
    private static final int ALL = 1, INCREMENT_BY_DICT = 2, INCREMENT_BY_TABLE = 3;

    /**
     * 0 0 0/1 * * ?
     */
    @XxlJob("dictionayMappingTaskForInternalTable")
    public void dictionayMappingTaskForInternalTable() {
        // 保存定时任务执行的时间戳s
        long start = System.currentTimeMillis();
        Date lastExeTime = null;
        try {
            lastExeTime = commonConfigService.getDictionaryMappingTaskLastExeTime();
        } catch (Exception e) {
            // ignore
        }
        lastTaskExecuteTimeStamp = lastExeTime == null ? null : lastExeTime.getTime();
        currentTaskExecuteTimeStamp = start / 1000;

        commonConfigService.save(
            CommonConfigKeyEnum.DICTIONARY_TASK_TIME_KEY, String.valueOf(start / 1000));
        log.info("[字典映射-内部数据源]任务开始执行");
        List<ProjectDomain> projects = projectService.getAllProject();

        if (CollectionUtils.isEmpty(projects)) {
            return;
        }
        projects.forEach(
            project -> {
                try {
                    this.projectDictMapping(project);
                } catch (Exception e) {
                    log.error("{}：[字典映射-内部数据源]任务执行失败,异常原因:{}", project.getName(), e.getMessage());
                }
            });
        long end = System.currentTimeMillis();
        log.info("[字典映射-内部数据源]任务执行成功，耗时：{}s", (end - start) / 1000.0D);
    }

    private void projectDictMapping(ProjectDomain project) {
        Long projectId = project.getId();
        DataSourceEntity defaultHiveDS = commonService.getSystemDateSource(projectId);
        String dsType = defaultHiveDS.getDsType();
        String dbName;
        if (dsType.equalsIgnoreCase(DSType.Hive.name())) {
            dbName = defaultHiveDS.getHiveConfig().getDbName();
        } else {
            dbName = defaultHiveDS.getRdbmsConfig().getDbName();
        }

        Long datasourceBaseId = Optional.ofNullable(defaultHiveDS).map(ds -> ds.getId()).orElse(0L);

        // 不能理解，先删了
        //    if (null != lastTaskExecuteTimeStamp) {
        //      // 处理已删除的表
        //      dictionaryMappingService.handleDeletedHiveTables(projectId, dbName);
        //    }
        // 根据定时任务的执行时间获取字典
        List<DictionaryDomain> changedDicts = null, allDicts = null;
        allDicts =
            dictionaryService.getDictionaryByProjectIdAndTaskTime(
                projectId, null, new Date(currentTaskExecuteTimeStamp * 1000));
        //    if (null == lastTaskExecuteTimeStamp) {
        List<Long> allDictIds =
            allDicts.stream().map(dict -> dict.getId()).collect(Collectors.toList());
        dictionaryMappingService.saveDictionaryMappingByDictIds(projectId, allDictIds);
        processStage(
            DictMappingParam.builder()
                .projectId(projectId)
                .dbName(dbName)
                .databaseId(datasourceBaseId)
                .dicts(allDicts)
                .type(ALL)
                .build());
        //    } else {
        // 2.增量
        changedDicts =
            dictionaryService.getDictionaryByProjectIdAndTaskTime(
                projectId,
                new Date(lastTaskExecuteTimeStamp * 1000),
                new Date(currentTaskExecuteTimeStamp * 1000));
        // 后加的
        // changedDicts = dictionaryMappingService.getMissMapping(projectId, changedDicts);
        // 2.1增量字典+所有表
        if (CollectionUtils.isNotEmpty(changedDicts)) {
            // 字典 删除 or 下线
            changedDicts.stream()
                .filter(
                    cd ->
                        cd.getRowState() == 0
                            || (cd.getReleaseStatus() == 0
                            && dictionaryMappingService.countByProjectIdAndDictId(
                            projectId, cd.getId())
                            > 0))
                .forEach(
                    dict -> {
                        DictionaryMappingDomain dictionaryMapping =
                            dictionaryMappingService.getDictMappingByProjectAndDict(
                                projectId, dict.getId());
                        if (dictionaryMapping.getBoundCount() > 0
                            || dictionaryMapping.getNotBoundCount() > 0) {
                            // 更新映射报告 hitcount
                            dictionaryMappingReportService.updateHitCountWhenDeleteDictionary(
                                dictionaryMapping.getId());
                            dictionaryMappingDetailService.deleteByDictMappingId(dictionaryMapping.getId());
                        }
                        dictionaryMappingService.deleteById(dictionaryMapping.getId());
                    });
            // 字典新增 or 上线
            changedDicts =
                changedDicts.stream()
                    .filter(
                        cd ->
                            cd.getCreateTime().getTime() >= lastTaskExecuteTimeStamp * 1000
                                || (cd.getReleaseStatus() == 1
                                && cd.getRowState() == 1
                                &&
                              /*cd.getCreateTime().getTime() < lastTaskExecuteTimeStamp*1000 &&
                              cd.getReleaseTime().getTime() >= lastTaskExecuteTimeStamp * 1000
                              &&*/ dictionaryMappingService
                                .countByProjectIdAndDictId(projectId, cd.getId())
                                == 0))
                    .collect(Collectors.toList());
            List<Long> newDictIds =
                changedDicts.stream().map(newDict -> newDict.getId()).collect(Collectors.toList());
            dictionaryMappingService.saveDictionaryMappingByDictIds(projectId, newDictIds);
            processStage(
                DictMappingParam.builder()
                    .projectId(projectId)
                    .dbName(dbName)
                    .databaseId(datasourceBaseId)
                    .dicts(changedDicts)
                    .type(INCREMENT_BY_DICT)
                    .build());
        }
        // 2.2 增量表+所有字典
        this.processStage(
            DictMappingParam.builder()
                .projectId(projectId)
                .dbName(dbName)
                .databaseId(datasourceBaseId)
                .dicts(allDicts)
                .type(INCREMENT_BY_TABLE)
                .build());
        //    }
    }

    private void processStage(DictMappingParam param) {
        Integer type = param.getType();
        List<TableInfoDomain> tables = null;
        if (type == ALL || type == INCREMENT_BY_DICT) { // 全量表 字典变化，增量字典+所有表
            tables =
                dictionaryMappingService.getHiveTablesForDictMapping(
                    param.getProjectId(), param.getDbName(), null);
        } else if (type == INCREMENT_BY_TABLE) { // 表变化，增量表+所有字典
            // 2/24验证下
            tables =
                dictionaryMappingService.getHiveTablesForDictMapping(
                    param.getProjectId(), param.getDbName(), lastTaskExecuteTimeStamp);
        }
        tables.forEach(
            table -> {
                String tableName = table.getTableName();
                TblPropEntity tblProp =
                    tblPropService.getTblPropBySchemaTblName(
                        param.getProjectId(), table.getSchema(), tableName);
                if (Objects.nonNull(tblProp)) {
                    table.setTblId(tblProp.getTblId());
                } else {
                    SaveNewTblPropParam saveNewTblPropParam = new SaveNewTblPropParam();
                    saveNewTblPropParam.setProjectId(param.getProjectId());
                    saveNewTblPropParam.setTblId(tblPropService.generateTblId(param.getProjectId()));
                    saveNewTblPropParam.setSchema(table.getSchema());
                    saveNewTblPropParam.setTableName(tableName);
                    saveNewTblPropParam.setTblType(TableInfoDomain.TblType.MANAGED_TABLE.name());
                    // default -1
                    saveNewTblPropParam.setLifeCycle(-1);
                    TblPropEntity insertEntity = tblPropService.saveNewTblPropEntity(saveNewTblPropParam);

                    table.setTblId(insertEntity.getTblId());
                }
            });
        // TODO
        StorageEntity storage = commonService.getStorage(param.getProjectId());
        param.setJdbcUrl(storage.getStorageLink());
        param.setTables(tables);
        param.setSchema(storage.getRmdbs().getSchema());
        param.setDbType(storage.getStorageType());
        this.tablesDictsMapping(param);
    }

    private void tablesDictsMapping(DictMappingParam dictMappingParam) {
        Long projectId = dictMappingParam.getProjectId();
        String dbName = dictMappingParam.getDbName();
        String jdbcUrl = dictMappingParam.getJdbcUrl();
        List<TableInfoDomain> tables = dictMappingParam.getTables();
        List<DictionaryDomain> dictionaries = dictMappingParam.getDicts();
        Integer type = dictMappingParam.getType();
        Long databaseId = dictMappingParam.getDatabaseId();
        String dbType = dictMappingParam.getDbType();
        String schema = dictMappingParam.getSchema();
        if (CollectionUtils.isEmpty(tables)) {
            return;
        }
        // BaseDbManager dbManager = commonService.getStorageDbManagerByProjctId(projectId);
        DataSourceEntity systemDataSourceDetail =
            datasourceBaseService.getSystemDataSourceDetail(projectId);
        DataSourceManagerDomain managerInfo =
            datasourceBaseService.getManagerInfo(systemDataSourceDetail.getId());
        BaseDbManager dbManager = managerInfo.getDbManager();
        try {
            for (TableInfoDomain table : tables) {
                try {
                    List<FieldInfoDomain> fieldList = Lists.newArrayList();
                    if (Objects.equals(dbType, "PostgreSQL")) {
                        fieldList = dbManager.getFieldList(table.getSchema(), table.getTableName());
                    } else if (Objects.equals(dbType, "Sap")) {
                        fieldList = dbManager.getFieldList(table.getDbName(), table.getTableName());
                    } else {
                        fieldList = dbManager.getFieldList(dbName, table.getTableName());
                    }
                    // 操作映射报告主表
                    DictionaryMappingReportDomain dictionaryMappingReport = null;

                    if (type == INCREMENT_BY_DICT || type == INCREMENT_BY_TABLE) {
                        dictionaryMappingReport =
                            dictionaryMappingReportService.getReportByProjectIdAndTblId(
                                projectId, table.getTblId());
                        //            dictionaryMappingReport =
                        //                dictionaryMappingReportService.getReportByProjectIdAndTblInfo(
                        //                    projectId, jdbcUrl, dbName, table.getTableName());
                        if (null != dictionaryMappingReport) {
                            dictionaryMappingReport.setFieldCount(fieldList.size());
                            dictionaryMappingReport.setUpdateTime(new Date());
                            // 更新映射报告fieldCount/fieldjson/tableComment
                            dictionaryMappingReportService.updateFieldById(
                                dictionaryMappingReport.getId(),
                                dictionaryMappingReport.getFieldCount(),
                                JSON.toJSONString(ConvertUtil.copyProperties(fieldList, FieldDomain.class)),
                                table.getTableName(),
                                table.getTableComment());
                        }
                    }
                    if (null == dictionaryMappingReport) {
                        DictionaryMappingReportParam reportParam =
                            DictionaryMappingReportParam.builder()
                                .projectId(projectId)
                                .tblId(table.getTblId())
                                .tableName(table.getTableName())
                                .tableDes(table.getTableComment())
                                .fieldCount(fieldList.size())
                                .tableDes(table.getTableComment())
                                .tableFieldJson(
                                    JSON.toJSONString(ConvertUtil.copyProperties(fieldList, FieldDomain.class)))
                                .datasourceBaseId(databaseId)
                                .dbName(dbName)
                                .jdbcUrl(jdbcUrl)
                                .build();
                        dictionaryMappingReport =
                            dictionaryMappingReportService.saveReportForHiveTable(reportParam);
                    }

                    DictMappingParam param =
                        DictMappingParam.builder()
                            .projectId(projectId)
                            .tblId(table.getTblId())
                            .dicts(dictionaries)
                            .fields(fieldList)
                            .type(type)
                            .dictionaryMappingReport(dictionaryMappingReport)
                            .build();
                    this.tableDictsMapping(param);
                } catch (SQLException throwables) {
                    log.error("[字典映射]定时任务执行失败,异常原因:{}", throwables.getMessage());
                }
            }
        } catch (Exception e) {
            // ignore
        } finally {
            dbManager.close();
        }
    }

    // 单表字典映射-字典变化
    private void tableDictsMapping(DictMappingParam param) {
        List<DictionaryDomain> dictionaries = param.getDicts();
        Long projectId = param.getProjectId();
        Long tblId = param.getTblId();
        String tableName = param.getTableName();
        List<FieldInfoDomain> fields = param.getFields();
        int type = param.getType();
        DictionaryMappingReportDomain dictionaryMappingReport = param.getDictionaryMappingReport();

        if (CollectionUtils.isEmpty(dictionaries) || CollectionUtils.isEmpty(fields)) {
            return;
        }
    /*List<String> dictEnNames =
    dictionaries.stream().map(d -> d.getDictNameEn()).collect(Collectors.toList());*/
        for (DictionaryDomain dict : dictionaries) {
            String dictNameCn = dict.getDictNameCn();
            String dictNameEn = dict.getDictNameEn();
            List<FieldInfoDomain> filteredFields =
                fields.stream()
                    .filter(
                        field -> dictNameEn.equalsIgnoreCase(field.getFieldName())
                  /*|| (dictNameCn.equals(field.getComment())
                  && !dictEnNames.contains(field.getFieldName()))*/)
                    .collect(Collectors.toList());
            DictionaryMappingDomain dictionaryMapping =
                dictionaryMappingService.getDictMappingByProjectAndDict(projectId, dict.getId());
            DictMappingParam handleModifiedParam =
                DictMappingParam.builder()
                    .projectId(projectId)
                    .tblId(tblId)
                    .dicts(dictionaries)
                    .fields(filteredFields)
                    .dictionaryMapping(dictionaryMapping)
                    .dictionary(dict)
                    .dictionaryMappingReport(dictionaryMappingReport)
                    .build();
            // 首次全量or字典变化且字典的创建时间在上次定时任务执行结束之后
            if (type == ALL || type == INCREMENT_BY_DICT
      /*|| (type == INCREMENT_BY_DICT
      && dict.getCreateTime().getTime() >= lastTaskExecuteTimeStamp * 1000)*/) {
        /*if (CollectionUtils.isEmpty(filteredFields)) {
          return;
        }*/
                List<DictionaryMappingDetailParam> dictionaryMappingDetails = new ArrayList<>();
                for (FieldInfoDomain field : filteredFields) { // 映射详情
                    DictionaryMappingDetailParam mappingDetailParam =
                        DictionaryMappingDetailParam.builder()
                            .projectId(projectId)
                            .dictMappingId(dictionaryMapping.getId())
                            .tblId(tblId)
                            .tblName(tableName)
                            .fieldName(Optional.ofNullable(field.getFieldName()).orElse(""))
                            .fieldDes(Optional.ofNullable(field.getComment()).orElse(""))
                            .dictId(dict.getId())
                            .dictDataType(Optional.ofNullable(field.getFieldType()).orElse(""))
                            .dictDataLength(Optional.ofNullable(field.getColumnSize()).orElse(0))
                            .rowState(1)
                            .mapSource(0)
                            .createUserId(0L)
                            .updateUserId(0L)
                            .boundStatus(0)
                            .createTime(new Date())
                            .updateTime(new Date())
                            .build();
                    dictionaryMappingDetails.add(mappingDetailParam);
                    dictionaryMapping.setNotBoundCount(
                        Optional.ofNullable(dictionaryMapping.getNotBoundCount()).orElse(0) + 1);
                    dictionaryMappingReport.setHitCount(
                        Optional.ofNullable(dictionaryMappingReport.getHitCount()).orElse(0) + 1);
                }
                dictionaryMappingDetailService.saveDictMappingDetailList(dictionaryMappingDetails);
                // 更新主表
                dictionaryMappingService.updateBoundCountById(
                    dictionaryMapping.getId(), 0, filteredFields.size());
                // 更新映射报告主表
                dictionaryMappingReportService.updateHitCountById(
                    dictionaryMappingReport.getId(), dictionaryMappingReport.getHitCount());
            } /*else if (type == INCREMENT_BY_DICT
            && dict.getCreateTime().getTime() < lastTaskExecuteTimeStamp * 1000) {
          // 2、定时任务执行之后变化的字典-字典更新
          dictionaryMappingService.handleDictMappingAfterDictOrTableModified(
              handleModifiedParam);
        }*/ else if (type == INCREMENT_BY_TABLE) { // 增量表_所有字典
                // 3.1 table更新 tables删除单独处理
                dictionaryMappingService.handleDictMappingAfterDictOrTableModified(handleModifiedParam);
            }
        }
    }

    /**
     * 0 0 0/1 * * ?
     */
    @XxlJob("dictionayMappingTaskForExternalTable")
    public void dictionayMappingTaskForExternalTable() {
        long start = System.currentTimeMillis();
        log.info("[字典映射-外部数据源]任务开始执行");
        List<ProjectDomain> projects = projectService.getAllProject();
        if (CollectionUtils.isEmpty(projects)) {
            return;
        }
        for (ProjectDomain project : projects) {
            try {
                dictionaryMappingReportService.deleteReportByMapsource(project.getId(), 1);
                dictionaryMappingDetailService.deleteDetailByMapsource(project.getId(), 1);
                List<DictionaryDomain> dicts =
                    dictionaryService.getDictionaryByProjectIdAndTaskTime(
                        project.getId(), null, new Date());
                // TODO 关系型数据库列表
                List<Map<String, Object>> dictMappingExternalDbs =
                    dictionaryMappingService.getExternalDbByProjectId(project.getId());
                if (CollectionUtils.isEmpty(dictMappingExternalDbs)) {
                    continue;
                }
                for (Map<String, Object> ex_db : dictMappingExternalDbs) {
                    String isSystem = MapUtils.getString(ex_db, "isSystem");
                    if (Objects.equals(isSystem, "1")) {
                        continue;
                    }
                    String dsType = MapUtils.getString(ex_db, "dsType");
                    String jdbcUrl = MapUtils.getString(ex_db, "jdbcUrl");
                    String username = MapUtils.getString(ex_db, "username");
                    String password = MapUtils.getString(ex_db, "password");
                    String dbName = MapUtils.getString(ex_db, "dbName");
                    //                      HikariPool pool =
                    //                          HikariPoolUtil.getHikariPool(dsType, jdbcUrl,
                    // username, password);
                    //                      if (null == pool) {
                    //                        return;
                    //                      }
                    DictMappingParam dictMapping =
                        DictMappingParam.builder()
                            .projectId(project.getId())
                            .databaseId(MapUtils.getLong(ex_db, "id"))
                            .dbType(dsType)
                            .dicts(dicts)
                            .userName(username)
                            // .pool(pool)
                            .password(password)
                            .jdbcUrl(jdbcUrl)
                            .dbName(dbName)
                            .build();
                    this.dbDictMappingForExternal(dictMapping);
                    //                      try {
                    //                        if (null != pool) {
                    //                          pool.shutdown();
                    //                        }
                    //                      } catch (InterruptedException e) {
                    //                        log.error("关闭hikaripool异常：{}", e.getMessage());
                    //                      }
                }
            } catch (Exception throwables) {
                log.error("{}:字典映射-外部数据源定时任务执行失败,失败原因:{}", project.getName(), throwables.getMessage());
            }
        }
        long end = System.currentTimeMillis();
        log.info("[字典映射-外部数据源]任务执行成功，耗时：{}s", (end - start) / 1000.0D);
    }

    private void dbDictMappingForExternal(DictMappingParam param) {
        Long dsId = param.getDatabaseId();
        Long projectId = param.getProjectId();
        Database database = Database.from(param.getDbType());
        //    BaseDbManager dbManager =
        //        DbManagerFactory.getDbManager(
        //            database, new DbOptions(param.getUserName(), param.getPassword(),
        // param.getJdbcUrl()));
        DataSourceManagerDomain managerInfo = datasourceBaseService.getManagerInfo(dsId);
        BaseDbManager dbManager = managerInfo.getDbManager();
        try {
            List<TableInfoDomain> tableInfoDomains = Lists.newArrayList();
            if (dbManager.hasSchema()) {
                tableInfoDomains = dbManager.getTableList(param.getDbName(), param.getSchema());
            } else {
                tableInfoDomains = dbManager.getTableList(param.getDbName());
            }
            if (CollectionUtils.isNotEmpty(tableInfoDomains)) {
                List<String> tableList =
                    tableInfoDomains.stream()
                        .map(TableInfoDomain::getTableName)
                        .collect(Collectors.toList());
                List<String> dbnames =
                    tableInfoDomains.stream().map(TableInfoDomain::getDbName).collect(Collectors.toList());

                for (int i = 0; i < tableList.size(); i++) {
                    try {
                        List<FieldInfoDomain> fields = dbManager.getFieldList(dbnames.get(i), tableList.get(i));
                        param.setTableName(tableList.get(i));
                        param.setFields(fields);
                        dictionaryMappingService.tableDictMappingForExternal(param);
                    } catch (Exception throwables) {
                        log.error("执行[字典映射-外部数据源]异常,表名:{},异常原因:{}", tableList.get(i), throwables.getMessage());
                    }
                }
            }
        } catch (Exception e) {
            log.error("[字典映射]外部数据源，获取连接失败，异常原因：{}", e.getMessage());
        } finally {
            dbManager.close();
        }
        dictionaryMappingService.handleDictMappingForExternalTables(projectId);
    }

    /**
     * 获取字典任务最后一次执行时间
     *
     * @return lastTaskExecuteTimeStamp
     */
    public String getLastTaskExecuteTimeStamp() {
        return Optional.ofNullable(lastTaskExecuteTimeStamp)
            .map(e -> e * 1000)
            .map(DateTime::of)
            .map(DateTime::toString)
            .orElse("");
    }
}
